package com.example.rfb.serviceloader.app_compiler;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
import javax.tools.Diagnostic;

import androidx.annotation.Keep;

public class ServicePoolGenerator {

    ServicePoolGenerator() {
    }

    static void write(Map<String, List<String>> result, ProcessingEnvironment processingEnvironment) throws IOException {
        Filer filer = processingEnvironment.getFiler();
        Messager messager = processingEnvironment.getMessager();

        for(String service : result.keySet()){

            String[] parseResult = parseServiceName(service);
            String packageName = parseResult[0];
            String serviceName = parseResult[1];
            ClassName providerClassName = ClassName.get(packageName, "Provider_" + serviceName, new String[0]);
            ClassName interfaceClassName = ClassName.get("com.example.rfb.serviceloader.internal", "IServiceProvider", new String[0]);
            ClassName genericServiceClassName = ClassName.get(Class.class);
            Collection<String> implementsClassStrings = result.get(service);

            if (implementsClassStrings.isEmpty()) {
                messager.printMessage(Diagnostic.Kind.WARNING, "No Service For" + service);
            } else {
                StringBuilder stringBuilder = new StringBuilder();

                for(String implementsClassString : implementsClassStrings){
                    stringBuilder.append(implementsClassString).append(".class").append(",");
                    stringBuilder.append("\n");
                }

                String implClassStringResult = stringBuilder.substring(0, stringBuilder.length() - 2);
                MethodSpec provide = MethodSpec.methodBuilder("provide").returns(
                        ParameterizedTypeName.get(ClassName.get(Collection.class), new TypeName[]{genericServiceClassName}))
                        .addModifiers(new Modifier[]{Modifier.PUBLIC})
                        .addAnnotation(Override.class)
                        .addStatement("return $T.<$T>asList(" + implClassStringResult + ")", new Object[]{ClassName.get(Arrays.class), genericServiceClassName})
                        .build();

                TypeSpec injectClass = TypeSpec
                        .classBuilder(providerClassName.simpleName())
                        .addModifiers(new Modifier[]{Modifier.PUBLIC, Modifier.FINAL})
                        .addSuperinterface(interfaceClassName)
                        .addMethod(provide).addAnnotation(Keep.class).build();
                JavaFile javaFile = JavaFile.builder(providerClassName.packageName(), injectClass).build();
                javaFile.writeTo(filer);
            }
        }
    }

    static String[] parseServiceName(String service) {
        String packageName = service.substring(0, service.lastIndexOf("."));
        String serviceName = service.substring(service.lastIndexOf(".") + 1, service.length());
        return new String[]{packageName, serviceName};
    }
}
